package org.aceor.mddal.common.sqlparser.result.context;

import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.aceor.mddal.common.sqlparser.result.condition.ComparableOR;
import org.aceor.mddal.common.sqlparser.result.condition.ComparableUnit;
import org.aceor.mddal.common.sqlparser.result.object.Column;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 *  目标:找到分库分表字段的condition ==> 可以按分库分表拆分成不同的sql
 *  这里规定:分库分表字段间如果使用OR连接,会特殊构建ComparableOr.
 *  即(id IN(1,2,3) OR id between 5 and 8) and id > 2
 *  当id为分库分表字段时,Column(id):List[ComparableOR(IN,Between), ComparableUnit(>2)],其中List的两个元素默认and连接
 *  当id不为分库分表字段时,无视OR,Column(id):List[IN,Between,ComparableUnit(>2)]
 *  其中,IN使用ComparableOR表示的,Between使用ComparableAND表示
 * Created by lxue on 16/3/23.
 */
public class ConditionContext {
    /**
     * 每列的condition间的关系全都看成and
     */
    private Map<Column, List<ComparableUnit>> conditionMap = Maps.newHashMap();

    /**
     * OR操作符两边是否都是分库分表字段
     */
    private boolean hasShardingColumnOrCondition;

    public void addCondition(Column column, ComparableUnit comparableUnit) {
        if (conditionMap.containsKey(column)) {
            if (!hasShardingColumnOrCondition || !checkExistInComparableOR(comparableUnit, conditionMap.get(column))) {
                //1. hasShardingColumnOrCondition=false时无视OR
                //2. 避免进行OR操作的时候,add了ComparableOR(A,B),避免后面的visitor又解析到A,B时把A,B也add进来
                conditionMap.get(column).add(comparableUnit);
            }
        } else {
            List<ComparableUnit> comparableUnits = Lists.newArrayList();
            comparableUnits.add(comparableUnit);
            conditionMap.put(column, comparableUnits);
        }
    }

    private boolean checkExistInComparableOR(ComparableUnit comparableUnit, List<ComparableUnit> comparableUnits) {
        for (ComparableUnit unit : comparableUnits) {
            //重复直接过滤
            if (Objects.equal(unit, comparableUnit)) {
                return true;
            }
            //处理OR
            if (unit instanceof ComparableOR) {
                return ((ComparableOR)unit).containsComparableUnit(comparableUnit);
            }
        }
        return false;
    }

    public Map<Column, List<ComparableUnit>> getConditionMap() {
        return conditionMap;
    }

    public void setConditionMap(Map<Column, List<ComparableUnit>> conditionMap) {
        this.conditionMap = conditionMap;
    }

    public List<ComparableUnit> findConditionsByColumn(Column column) {
        if (!conditionMap.containsKey(column)) {
            return Collections.emptyList();
        } else {
            return conditionMap.get(column);
        }
    }

    public boolean isHasShardingColumnOrCondition() {
        return hasShardingColumnOrCondition;
    }

    public void setHasShardingColumnOrCondition(boolean hasShardingColumnOrCondition) {
        this.hasShardingColumnOrCondition = hasShardingColumnOrCondition;
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("ConditionMap", conditionMap)
                .toString();
    }
}
